<?
/**
* <b>Encryption</b>
*
* Encrypts stuff
* 
* @class encryption
* @package gravy.classes
*/
class encryption{
	#Once set do NOT, EVER change (per application).
	const STRING_SALT="[+];*7gHt5%43Fsd#";

	
	/**
	* <b>__construct</b>
	* @fn __construct
	* @return void
	*/
	public function __construct(){
	}

	/**
	* <b>rc4</b>
	* 
	* RC4 Encryption Routine, returns encrypted string.
	* 
	* @fn rc4
	* @param $str - string to be encrypted
	* @param $password - RC4 password
	* @return string
	*/
	static function rc4($str,$password){
		$cipher="";$i=0;$j=0;$b=0;
		$intLength=strlen($password);
		for($a=0;$a<=255;$a++){
			$key[$a]=ord(substr($password,($a%$intLength),1));
			$sbox[$a]=$a;
		}	
		for($a=0;$a<=255;$a++){
			$b=($b+$sbox[$a]+$key[$a])%256;
			$tempasswordap=$sbox[$a];
			$sbox[$a]=$sbox[$b];
			$sbox[$b]=$tempasswordap;
		}	
		for($a=0;$a<strlen($str);$a++){
			$i=($i+1)%256;
			$j=($j+$sbox[$i])%256;
			$temp=$sbox[$i];
			$sbox[$i]=$sbox[$j];
			$sbox[$j]=$temp;
			$k=$sbox[($sbox[$i]+$sbox[$j])%256];
			$cipherby=ord(substr($str,$a,1))^$k;
			$cipher.=chr($cipherby);
		}
		return($cipher);
	}
	
	/**
	* <b>rc4encrypt</b>
	* 
	* Returns hex result of RC encryption
	* 
	* @fn rc4encrypt
	* @param $str
	* @param $password
	* @return string
	*/
	static function rc4encrypt($str,$password){
		return(bin2hex(encryption::rc4($str,$password)));
	}
	
	/**
	* <b>rc4decrypt</b>
	* 
	* Decrypt rc4-encrypted string and return result
	* 
	* @fn rc4decrypt
	* @param $str
	* @param $password
	* @return string
	*/
	static function rc4decrypt($str,$password){
		return(encryption::rc4(encryption::hex2bin($str),$password));
	}
	
	/**
	* <b>hex2bin</b>
	* 
	* Reverses bin2hex (php) operation on a string and returns result.
	* 
	* @fn hex2bin
	* @param $hexdata
	* @return string
	*/
	static function hex2bin($hexdata){
		$bindata="";
		for($i=0;$i<strlen($hexdata);$i+=2){
			$bindata.=chr(hexdec(substr($hexdata,$i,2)));
		}
		return($bindata);
	}
	
	/**
	* <b>snis_encrypt</b>
	* 
	* Simple Numerical Index Shuffling - Encryption
	* Returns numerical string.
	* 
	* @fn snis_encrypt
	* @param $num
	* @param $pw
	* @return string
	*/
	static function snis_encrypt($num,$pw){
		$result="";
		$ascii="";
		$shuffled_index=0;
		#remove any non-numeric characters
		$num=preg_replace("/[^0-9]/i","",$num);

		#salt the password, and make it at least the length of the number.
		$pw=encryption::salt_string($pw,max(strlen($num),strlen($pw)));
		
		#shuffle the numbers 0-9 based on the supplied password
		$shuffled_nums=encryption::shuffle_numbers("0123456789",$pw);
		#reverse the order of the numeric characters
		$rev=strrev((string)$num);
		#loop throught the reversed numbers
		for($i=0;$i<strlen($rev);$i++){
			$pw_ind=$i;
			#get the ascii character of the password, at the current index
			$ascii=ord(substr($pw,$pw_ind,1));
			#sum the numbers that make up the ascii character code
			$pw_sum=0;
			for($j=0;$j<strlen((string)$ascii);$j++){
				$pw_sum+=(int)substr((string)$ascii,$j,1);
			}
			#get the mod 10 of the summed ascii code
			$pw_sum=$pw_sum%10;
			#add the summed, modded password ascii char to the number at the current index, which we'll call the shuffled_index
			$shuffled_index=$pw_sum+((int)substr($rev,$i,1));
			#make sure the shuffled_index is not larger than 10 (i.e. is only one character.
			$shuffled_index=($shuffled_index%10);
			if($shuffled_index==0){
				$shuffled_index=10;
			}
			#based on the shuffled numbers, get the character at 10-shuffled_index.
			$result.=substr($shuffled_nums,(string)(10-$shuffled_index),1);
		}
		return((string)$result);
	}
	
	/**
	* <b>snis_decrypt</b>
	* 
	* Simple Numerical Index Shuffling - Decryption
	* Returns numerical string.
	* 
	* @fn snis_decrypt
	* @param $num
	* @param $pw
	* @return string
	*/
	static function snis_decrypt($num,$pw){
		$result="";
		$ascii="";
		
		#remove any non-numeric characters
		$num=preg_replace("/[^0-9]/i","",$num);
		
		$pw=encryption::salt_string($pw,max(strlen($num),strlen($pw)));
		
		$shuffled_nums=encryption::shuffle_numbers("0123456789",$pw);
		
		#loop through each of the shuffled numbers, and convert back to original.
		for($i=0;$i<strlen($num);$i++){
			#get the encrypted character at the current index.
			$enc_char=substr((string)$num,$i,1);
			#get the index of the encrypted char within the shuffled numbers
			$ind=strpos($shuffled_nums,$enc_char);
			$shuffled_index=10-$ind;
			if($shuffled_index==10){
				$shuffled_index=0;
			}

			$pw_ind=$i;
			#get the ascii character of the password, at the current index
			$ascii=ord(substr($pw,$pw_ind,1));
			#sum the numbers that make up the ascii character code
			$pw_sum=0;
			for($j=0;$j<strlen((string)$ascii);$j++){
				$pw_sum+=(int)substr((string)$ascii,$j,1);
			}
			#get the mod 10 of the summed ascii code
			$pw_sum=$pw_sum%10;
			$res=($shuffled_index-$pw_sum);
			if($res<0){
				$res+=10;
			}
			$result.=(string)$res;
		}
		#reverse the order of the numeric characters, back to the final number.
		$result=strrev((string)$result);
		return((string)$result);
	}
	
	/**
	* <b>salt_string</b>
	* 
	* Salt's a string with the above salt-key (encryption::STRING_SALT), to a specified length.
	* Returns numerical string. 
	* 
	* @fn salt_string
	* @param $string
	* @param $length
	* @return string
	*/
	static function salt_string($string,$length){
		$result="";
		$c=0;
		
		$str_len=strlen($string);
		$str_pass=0;
		if($str_len<1){
			$str_len=1;
			$string="0";
		}
		$salt_len=strlen(encryption::STRING_SALT);
		$salt_pass=0;
		
		while(strlen($result)<$length){
			if($c>=$str_len){
				$str_pass++;
			}
			$str_char=substr($string,($c%$str_len),1);
			$str_ascii=ord($str_char)+$str_pass;
			
			if($c>=$salt_len){
				$salt_pass++;
			}
			$salt_char=substr(encryption::STRING_SALT,($c%$salt_len),1);
			$salt_ascii=ord($salt_char)+$salt_pass;
			
			$char=abs($str_ascii-$salt_ascii);
			
			#print("<h1>char:".$char."</h1>");
		
			$result.=chr(33+($char%93));
			$c++;
		}
		return($result);
	}
	
	/**
	* <b>shuffle_numbers</b>
	* 
	* Shuffles numbers based on a supplied string
	* Returns numerical string. 
	* 
	* @fn shuffle_numbers
	* @param $numbers
	* @param $key
	* @return string
	*/
	static function shuffle_numbers($numbers,$key){
		$result=$numbers;
		$new_key=$key;

		$new_key=encryption::salt_string($key,max(strlen($numbers),strlen($new_key)));

		$asc=0;
		$ar=array();
		for($c=0;$c<strlen($numbers);$c++){
			$ind=ord(substr($new_key,$c,1));
			while(array_key_exists($ind,$ar)){
				$ind=1+$ind*2;
			}
			#print("<h1>ind:".$ind."=".substr($numbers,$c,1)."</h1>");
			$ar[$ind]=substr($numbers,$c,1);
		}
		#$result=(string)join($ar);
		#print("<h1>unsorted:".$result."</h1>");
		ksort($ar);
		$result=(string)join($ar);
		#print("<h1>sorted:".$result."</h1>");
		return($result);
	}
		
	/**
	* <b>checksum</b>
	* 
	* Generate a checksum for the given number.
	* Returns numerical string.
	* 
	* @fn checksum
	* @param $number
	* @param $generate - [def=false]
	* @return void
	*/
	static function checksum($number,$generate=false){
		$result=$number;
		$checksum=0;
		#take out invalid characters
		$number=preg_replace("/\D/","",$number);
		if($generate){
			#duplicate the number 3 times
			$multi=$number.$number.$number;
		}else{
			$last_char=substr($number,-1);
			$number=substr($number,0,-1);
		}
		#parity
		$number_length=strlen($number);
		$parity=$number_length%2;
		#loop through the odd numbers and times them by 2
		for($c=1;$c<$number_length;$c+=2){
			$digit=$number[$c];
			#multiply alternate digits by two
			if($c%2==$parity){
				$digit*=2;
				#f the sum is two digits, add them together (in effect)
				if($digit>9){
					$digit-=9;
				}
			}
			// Total up the digits
			$checksum+=$digit;
		}
		$checksum=$checksum%10;
		if($generate){
			$result.=$checksum;
		}else{
			$result=($checksum==$last_char);
		}
		return($result);
	}
};
?>
